The Zambian Kwacha has seen a great deal of movements against the Dollar over the past 10 years, the purpose of this notebook is to explore and analyse the movements in the exchange rates over that past ten years to gain insight in the currency movements. This analysis will solely focus on the movements between the Zambian Kwacha (ZMW) against the United states Dollar ($).

Currency exchange rate forecasting means predicting future fluctuations in the value of one currency against another. It involves the use of historical data, economic indicators, and mathematical models to make accurate predictions about the direction and magnitude of exchange rate movements. This portion of the project will be focused on changes in the exchange rate and the forecasting is in the next section.

The source of the data used for my analysis is from the Zambian Central bank:The Bank of Zambia- USD/ZMW exchange rates

The results of this analysis can be used by policy makers and investors to manage the exchange rate risk of conducting business in zambia

In [1]:
#import the relevant Libraries
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import plotly.express as px
import plotly.graph_objects as go
import plotly.io as pio
from plotly.subplots import make_subplots
In [2]:
raw_data=pd.read_csv(r"C:\Users\Namukaba Katambo\Desktop\NK\Datasets for practice\DAILY_RATES 07182023.csv")
raw_data.head()
Out[2]:
DATE TIME BUYING RATE MID RATE SELLING RATE
0 1/2/2013 3:30:00 PM 5.24 5.250000 5.260000
1 1/2/2013 12:30:00 PM 5.217777778 5.227778 5.237778
2 1/2/2013 9:30:00 AM 5.161111111 5.171111 5.181111
3 1/3/2013 9:30:00 AM 5.259722222 5.269722 5.279722
4 1/3/2013 12:30:00 PM 5.238611111 5.248611 5.258611
In [3]:
#number of columns and rows
raw_data.shape
Out[3]:
(7836, 5)
In [4]:
#creating a copy of the dataframe
data=raw_data.copy()
In [5]:
data.shape
Out[5]:
(7836, 5)
In [6]:
#changing the text format of the column names
data.columns = data.columns.str.capitalize()
In [7]:
data.head()
Out[7]:
Date Time Buying rate Mid rate Selling rate
0 1/2/2013 3:30:00 PM 5.24 5.250000 5.260000
1 1/2/2013 12:30:00 PM 5.217777778 5.227778 5.237778
2 1/2/2013 9:30:00 AM 5.161111111 5.171111 5.181111
3 1/3/2013 9:30:00 AM 5.259722222 5.269722 5.279722
4 1/3/2013 12:30:00 PM 5.238611111 5.248611 5.258611
In [8]:
#Checking for missing values
data.isnull().sum()
Out[8]:
Date            0
Time            0
Buying rate     0
Mid rate        0
Selling rate    0
dtype: int64
In [9]:
#viewing the data types in the dataframe
data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 7836 entries, 0 to 7835
Data columns (total 5 columns):
 #   Column        Non-Null Count  Dtype  
---  ------        --------------  -----  
 0   Date          7836 non-null   object 
 1   Time          7836 non-null   object 
 2   Buying rate   7836 non-null   object 
 3   Mid rate      7836 non-null   float64
 4   Selling rate  7836 non-null   float64
dtypes: float64(2), object(3)
memory usage: 306.2+ KB
In [10]:
#Checking the details of the numerical data base
data.describe()
Out[10]:
Mid rate Selling rate
count 7836.000000 7836.000000
mean 12.230194 12.249947
std 5.088820 5.093707
min 5.171111 5.181111
25% 8.335764 8.345764
50% 10.970278 10.986944
75% 16.966953 16.991953
max 22.669275 22.694119
In [11]:
#changing the format of the date column and adding a month and year column for better analysis of the exchange rate movements
data["Date"] = pd.to_datetime(data["Date"], format = "%m/%d/%Y")
data['Year'] = data['Date'].dt.year
data["Month"] = data["Date"].dt.month
data.head()
Out[11]:
Date Time Buying rate Mid rate Selling rate Year Month
0 2013-01-02 3:30:00 PM 5.24 5.250000 5.260000 2013 1
1 2013-01-02 12:30:00 PM 5.217777778 5.227778 5.237778 2013 1
2 2013-01-02 9:30:00 AM 5.161111111 5.171111 5.181111 2013 1
3 2013-01-03 9:30:00 AM 5.259722222 5.269722 5.279722 2013 1
4 2013-01-03 12:30:00 PM 5.238611111 5.248611 5.258611 2013 1

Below graph shows the overrall exchange rate movements over the defined period(2013-2023)

In [12]:
figure = px.line(data, x="Date", 
                 y="Selling rate", 
                 title='USD/KMW Conversion Rate over the years 2013-2023')
figure.show()

The chart below will show the decomposition of exchange rates into seasonal, trend, and residual components.

  1.The trend component represents the long-term movement or the overall direction of the exchange rate. It shows the   underlying growth or decline in the exchange rate that is not attributable to seasonal or random fluctuations
  2.The seasonal component captures the regular and repeated patterns that occur at fixed intervals, such as monthly, quarterly, or yearly cycles
  3.The residual component, represents the unexplained variation in the data after accounting for the trend and seasonal components.
In [13]:
import statsmodels.api as sm

# Perform seasonal decomposition using statsmodels
decomposition = sm.tsa.seasonal_decompose(data['Selling rate'], model='additive', period=12)

# Extract the components: trend, seasonal, and residual
trend = decomposition.trend
seasonal = decomposition.seasonal
residual = decomposition.resid

# Create the seasonal decomposition chart using Plotly
fig = go.Figure()

fig.add_trace(go.Scatter(x=data['Date'], y=trend, mode='lines', name='Trend'))
fig.add_trace(go.Scatter(x=data['Date'], y=seasonal, mode='lines', name='Seasonal'))
fig.add_trace(go.Scatter(x=data['Date'], y=residual, mode='lines', name='Residual'))

fig.update_layout(title='Seasonal Decomposition of Exchange Rate',
                  xaxis_title='Date',
                  yaxis_title='Exchange Rate',
                  xaxis=dict(tickangle=-45),
                  template='plotly_white')

fig.show()

-From the chart we can observe a general upward trend in the exchange rate meaning generally theres a depreciation of the kwacha against the dollar

-the seasonal component is not defined.

-There is a large residual component during certain periods suggesting that there are significant unpredictable movements in the exchange rate that are not accounted for by the trend and seasonality.

Calculating the percentage growth/change of the USD/ZMW over the past 10 years

In [14]:
yearly_rate_change = data.groupby('Year').agg({'Selling rate': lambda x: (x.iloc[-1]-x.iloc[0])/x.iloc[-1]*100})

fig = go.Figure()
fig.add_trace(go.Bar(x=yearly_rate_change.index,
                     y=yearly_rate_change['Selling rate'],
                     name='Yearly Change'))

fig.update_layout(title="Yearly Overrall Change(%) of USD againt ZMW Conversion Rate",
                  xaxis_title="Year",
                  yaxis_title="Change (%)",
                  width=900,
                  height=600)

pio.show(fig)

Observations from the above Chart are:¶

1 2015 experineced the greatest loss in value of the kwacha depreciating an overrall 41%
2 2016 the kwacha gained an overrall 11% in value
3 through out 2017 and 2019 the kwacha lost value against the dollar with 2020 recording the second largest drop in value of 33%
4 2021 saw largest gain in the exchange rate, with the kwacha appreciating an overrall 27%
In [15]:
# Calculate monthly growth
data['Growth'] = data.groupby(['Year', 'Month'])['Selling rate'].transform(lambda x: (x.iloc[-1] - x.iloc[0]) / x.iloc[-1] *100)

# Group data by Month and calculate average growth
grouped_data = data.groupby('Month').mean().reset_index()

fig = go.Figure()

fig.add_trace(go.Bar(
    x=grouped_data['Month'],
    y=grouped_data['Growth'],
    marker_color=grouped_data['Growth'],
    hovertemplate='Month: %{x}<br>Average Growth: %{y:.2f}%<extra></extra>'
))

fig.update_layout(
    title="Aggregated Monthly Growth of USD - ZMW Conversion Rate",
    xaxis_title="Month",
    yaxis_title="Average Growth (%)",
    width=900,
    height=600
)

pio.show(fig)

From the graph above we can notice that on average the value of the USD is growing in the first quater of the year, drastically reduces in April and has a sharp increament in May. The USD has it greatest gain on avergae during the 3rd Quater of the year with record gains of about 7.13% on average in September. The last Quater of the years sees a steady decline in the value of the USD against the kwacha.

In [16]:
#creating a dataframe of the averge USD/ZMW rates for further analysis
df= data.groupby(['Year', 'Month']).agg({'Selling rate': 'mean'})
df=df.reset_index()
# Pivot the table to have years as columns
df_pivot = df.pivot_table(index='Month', columns='Year', values='Selling rate')
df_pivot
Out[16]:
Year 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023
Month
1 5.297792 5.532549 6.480154 11.138722 9.953333 9.882109 11.958134 14.438074 21.320744 17.288466 18.541824
2 5.341868 5.696115 6.759163 11.340276 9.787736 9.817583 11.943695 14.715672 21.614575 18.121685 19.430521
3 5.389263 6.098510 7.367764 11.354370 9.622815 9.610848 12.056956 16.547235 22.010959 17.959608 20.761374
4 5.369843 6.208556 7.402171 9.753113 9.468533 9.546208 12.329681 18.613328 22.239085 17.418853 18.478585
5 5.332128 6.627141 7.269625 10.067181 9.280600 10.115878 13.285192 18.249721 22.456836 17.114484 18.607818
6 5.427195 6.315078 7.340320 10.726582 9.278523 10.069474 13.078157 18.209666 22.605631 17.035664 18.757500
7 5.491058 6.158970 7.681049 9.926613 8.943723 9.913695 12.770145 18.177993 21.649682 16.448723 18.368262
8 5.434596 6.118421 8.103855 10.035591 9.043807 10.120057 13.059671 18.807848 18.093191 16.104730 NaN
9 5.341492 6.156435 10.209129 10.002178 9.419757 10.976490 13.165548 19.849005 16.398573 15.646951 NaN
10 5.327931 6.342253 12.026660 9.906481 9.782705 11.939002 13.203160 20.223712 17.061367 15.947351 NaN
11 5.532100 6.355074 12.186176 9.843612 10.066454 11.870455 14.001909 20.859575 17.569364 16.573000 NaN
12 5.536000 6.350156 10.848764 9.868240 10.051031 11.937557 14.402544 21.113726 16.808671 17.607835 NaN
In [17]:
#creating a heat map showing the changes in exchange rates and the colors represent the magnitute of changes
fig = go.Figure(data=go.Heatmap(z=df_pivot.values, x=df_pivot.columns, y=df_pivot.index,
                                colorscale='Viridis'))

fig.update_layout(title='Exchange Rate Movements - Heatmap',
                  xaxis_title='Years',
                  yaxis_title='Months',
                  xaxis=dict(tickmode='array', tickvals=list(df_pivot.columns)),
                  yaxis=dict(tickmode='array', tickvals=list(range(1, 13)),
                             ticktext=['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']),
                  template='plotly_white')

fig.show()

Showcasing the exchange rate movements over the years per year

In [18]:
traces = []
for year in df_pivot.columns:
    trace = go.Scatter(
        x=df_pivot.index,
        y=df_pivot[year],
        mode='lines+markers',
        name=str(year)
    )
    traces.append(trace)

# Create the layout
layout = go.Layout(
    title='Exchange Rate Movement by Year',
    xaxis=dict(title='Month'),
    yaxis=dict(title='Exchange Rates')
)

# Create the figure
fig = go.Figure(data=traces, layout=layout)

# Show the plot
fig.show()
In [ ]: